use std::{fs, error::Error, env};
use std::env::Args;

pub struct Config {
    pub query: String,
    pub filename: String,
    pub case_sensitive: bool,
}

impl Config {
    pub fn new(mut args:Args) -> Result<Config, &'static str> {
        args.next();
        let query = match args.next() {
            Some(arg)=>arg,
            None=>{
                return Err("query field missing");
            }
        };
        let filename = match args.next() {
            Some(arg)=>arg,
            None=>{
                return Err("filename field missing");
            }
        };
        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
        Ok(Config {query, filename, case_sensitive})
    }
}


pub fn run(conf: Config) -> Result<(), Box<dyn Error>> {
    let content = fs::read_to_string(conf.filename)?;
    println!("Search result contains \"{}\":", conf.query);
    println!("==============");

    let result = if conf.case_sensitive{
        case_sensitive_search(&conf.query, &content)
    }else{
        case_insensitive_search(&conf.query, &content)
    };

    for line in result{
        println!("{}", line);
    }
    Ok(())
}

pub fn case_insensitive_search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    content.lines().filter(|line|line.to_lowercase().contains(&query.to_lowercase())).collect()
    // let mut res = Vec::new();
    // for line in content.lines() {
    //     if line.to_lowercase().contains(&query.to_lowercase()) {
    //         res.push(line.trim());
    //     }
    // }
    // res
}

pub fn case_sensitive_search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    content.lines().filter(|line| line.contains(&query)).collect()
    // let mut res = Vec::new();
    // for line in content.lines() {
    //     if line.contains(&query) {
    //         res.push(line.trim());
    //     }
    // }
    // res
}


#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn one_result(){
        let query="duct";
        let content = "\
        Rust:
        safe, fast, productive.
        Pick three.";
        assert_eq!(
            vec!["safe, fast, productive."],
            case_insensitive_search(query, content)
        )
    }

    #[test]
    fn case_insensitive(){
        let query = "rUst";
        let contents = "\
        Rust:
        safe, fast, productive.
        Pick three.
        Trust me.";
        assert_eq!(vec!["Rust:", "Trust me."], case_insensitive_search(query, contents));
    }

    #[test]
    fn case_sensitive(){
        let query = "Rust";
        let contents = "\
        Rust:
        safe, fast, productive.
        Pick three.
        Trust me.";
        assert_eq!(vec!["Rust:"], case_sensitive_search(query, contents));
    }

}